﻿using System.Diagnostics;

namespace DataStructure;

public class SpecialMatrix
{
    public static T[] SymmetricMatrixCompress<T>(T[,] symmetricMatrix)
    {
        Console.WriteLine("SymmetricMatrix Compressed To 1D Array: ");
        int N = symmetricMatrix.GetLength(0);
        int count = N * (N + 1) / 2;
        T[] compArr = new T[count];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j <N; j++)
            {
                if (j <= i)
                {
                    compArr[i * (i + 1) / 2 + j] = symmetricMatrix[i, j];
                }
            }
        }
        return compArr;
    }

    public static T[,] SymmetricMatrixDecompress<T>(T[] compArr)
    {
        Console.WriteLine("1D Array Decompressed To SymmetricMatrix: ");

        //N*(N+1)/2=compArr.Length => N=?
        int N = (int)Math.Ceiling(-1 + Math.Sqrt(1 + 8 * compArr.Length) / 2);

        T[,] symMatrix = new T[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j <= i; j++)
            {
                symMatrix[i, j] = compArr[i * (i + 1) / 2 + j];
                symMatrix[j, i] = symMatrix[i, j];
            }
        }

        return symMatrix;
    }

    public static T[] LeftLowerTriangularMatrixCompress<T>(T[,] leftLowerTriangularMatrix)
    {
        Console.WriteLine("LeftLowerTriangularMatrix Compressed To 1D Array: ");

        int N = leftLowerTriangularMatrix.GetLength(0);
        int count = N * (N + 1) / 2 + 1;

        T[] compArr = new T[count];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j <= i; j++)
            {
                compArr[i * (i + 1) / 2 + j] = leftLowerTriangularMatrix[i, j];
            }
        }
        compArr[N * (N + 1) / 2] = leftLowerTriangularMatrix[0, N - 1];

        return compArr;
    }

    public static T[,] LeftLowerTriangularMatrixDecompress<T>(T[] compArr)
    {
        Console.WriteLine("1D Array Decompressed To LeftLowerTriangularMatrix: ");

        //N*(N+1)/2+1=compArr.Length => N=?
        int N = (int)Math.Ceiling(-1 + Math.Sqrt(-7 + 8 * compArr.Length) / 2);

        T[,] lowTriMatrix = new T[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (j <= i)
                {
                    lowTriMatrix[i, j] = compArr[i * (i + 1) / 2 + j];
                }
                else
                {
                    lowTriMatrix[i, j] = compArr[compArr.Length - 1];
                }
            }
        }

        return lowTriMatrix;
    }

    public static T[] RightUpperTriangularMatrixCompress<T>(T[,] rightUpperTriangularMatrix)
    {
        Console.WriteLine("RightUpperTriangularMatrix Compressed To 1D Array: ");

        int N = rightUpperTriangularMatrix.GetLength(0);
        int count = N * (N + 1) / 2 + 1;

        T[] compArr = new T[count];
        for (int i = 0; i < N; i++)
        {
            for (int j = i; j < N; j++)
            {
                compArr[i * (2 * N - i + 1) / 2 + j - i] = rightUpperTriangularMatrix[i, j];
            }
        }
        compArr[N * (N + 1) / 2] = rightUpperTriangularMatrix[N - 1, 0];

        return compArr;
    }

    public static T[,] RightUpperTriangularMatrixDecompress<T>(T[] compArr)
    {
        Console.WriteLine("1D Array Decompressed To RightUpperTriangularMatrix: ");

        //N*(N+1)/2+1=compArr.Length => N=?
        int N = (int)Math.Ceiling(-1 + Math.Sqrt(-7 + 8 * compArr.Length) / 2);

        T[,] upperTriMatrix = new T[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (j >= i)
                {
                    upperTriMatrix[i, j] = compArr[i * (2 * N - i + 1) / 2 + j - i];
                }
                else
                {
                    upperTriMatrix[i, j] = compArr[compArr.Length - 1];
                }
            }
        }

        return upperTriMatrix;
    }

    public static T[] TripleDiagonalMatrixCompress<T>(T[,] tripleDiagonalMatrix)
    {
        Console.WriteLine("TripleDiagonalMatrix Compressed To 1D Array: ");

        int N = tripleDiagonalMatrix.GetLength(0);
        int count = 3 * N - 2;

        T[] compArr = new T[count];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (j >= i - 1 && j <= i + 1)
                {
                    compArr[2 * i + j] = tripleDiagonalMatrix[i, j];
                }
            }
        }

        return compArr;
    }

    public static T[,] TripleDiagonalMatrixDecompress<T>(T[] compArr)
    {
        Console.WriteLine("1D Array Decompressed To TripleDiagonalMatrix: ");

        //3*N-2=compArr.Length => N=?
        int N = (int)Math.Ceiling((2 + (double)compArr.Length) / 3);

        T[,] diagonalTriMatrix = new T[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (j >= i - 1 && j <= i + 1)
                {
                    diagonalTriMatrix[i, j] = compArr[2 * i + j];
                }
                else
                {
                    diagonalTriMatrix[i, j] = default;
                }
            }
        }

        return diagonalTriMatrix;
    }

    static void Main(string[] args)
    {
        //对称矩阵
        int[,] symMatrix =
        {
            {8, 3, 4, 2, 1, },
            {3, 6, 9, 7, 3, },
            {4, 9, 5, 2, 4, },
            {2, 7, 2, 7, 6, },
            {1, 3, 4, 6, 0, },
        };

        var compressSymArr1D = SymmetricMatrixCompress(symMatrix);
        compressSymArr1D.Print();

        var rebuiltSymMatrix = SymmetricMatrixDecompress(compressSymArr1D);
        ArrayMap.Print(rebuiltSymMatrix);

        //左下三角矩阵
        int[,] leftLowerTriangularMatrix =
        {
            {8, 9, 9, 9, 9, },
            {3, 6, 9, 9, 9, },
            {4, 9, 5, 9, 9, },
            {2, 7, 2, 7, 9, },
            {1, 3, 4, 6, 0, },
        };

        var compressLowTriArr1D = LeftLowerTriangularMatrixCompress(leftLowerTriangularMatrix);
        ArrayMap.Print(compressLowTriArr1D);

        var rebuiltLowTriMatrix = LeftLowerTriangularMatrixDecompress(compressLowTriArr1D);
        ArrayMap.Print(rebuiltLowTriMatrix);

        //右上三角矩阵        
        int[,] rightUpperTriangularMatrix = //k=n+(n-1)+...+(n-i+1)=i*(n+n-i+1)/2+j-i
        {
            {8, 3, 4, 2, 1, },
            {9, 6, 9, 7, 3, },
            {9, 9, 5, 2, 4, },
            {9, 9, 9, 7, 6, },
            {9, 9, 9, 9, 0, },
        };

        var compressUpperTriArr1D = RightUpperTriangularMatrixCompress(rightUpperTriangularMatrix);
        ArrayMap.Print(compressUpperTriArr1D);

        var rebuiltUpperTriMatrix = RightUpperTriangularMatrixDecompress(compressUpperTriArr1D);
        ArrayMap.Print(rebuiltUpperTriMatrix);

        //三对角矩阵
        int[,] tripleDiagonalMatrix =
        {
            {8, 2, 0, 0, 0, },
            {3, 6, 8, 0, 0, },
            {0, 9, 5, 9, 0, },
            {0, 0, 2, 7, 1, },
            {0, 0, 0, 6, 4, },
        };

        var compressTriDiagArr1D = TripleDiagonalMatrixCompress(tripleDiagonalMatrix);
        ArrayMap.Print(compressTriDiagArr1D);

        var rebuiltTriDiagMatrix = TripleDiagonalMatrixDecompress(compressTriDiagArr1D);
        ArrayMap.Print(rebuiltTriDiagMatrix);
    }
}
